# coding: utf-8
import os
import win32gui
import win32con
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium import webdriver
import time
from config.globalVars import G
from utils.Others.logOperation import logger


class basePage(object):
    def __init__(self, driver: webdriver.Remote):
        self.browser = driver
        self.log = logger()

    def _locate_element(self, locator):
        """
        to locate element by selector
        :arg
        selector should be passed by an example with "i,xxx"
        "x,//*[@id='langs']/button"
        :returns
        DOM element
        """
        if locator is not None:
            element = self.browser.find_element(*locator)
        else:
            raise NameError("找不到指定的目标元素%s！" % locator)
        return element

    # 寻找元素
    def find_element(self, loc):
        return self._find_element(*loc)

    def _find_element(self, *loc):
        try:
            # 加一个显式等待，元素加载成功
            WebDriverWait(self.browser, 10).until(EC.visibility_of_all_elements_located(loc))
            element = self.browser.find_element(*loc)
            self.log.info("%s页面找到了%s元素" % (self, loc))
            return element
        except AttributeError:
            self.log.info("%s页面中未能找到%s元素" % (self, loc))

    # 填写文本框
    def send_keys(self, loc, keyword, click_f=True, clear_f=True):
        try:
            # getattr相当于实现self.loc(将元组变成可调用的变量)
            # loc = getattr(self,"_%s"% loc)
            if click_f:
                self.find_element(loc).click()
            if clear_f:
                self.find_element(loc).clear()
            self.find_element(loc).send_keys(keyword)
        except AttributeError:
            print("%s页面中未能找到%s元素" % (self, loc))

    # 切换frame页
    def switch_to_frame(self, loc):
        iframe = self.find_element(loc)
        return self.browser.switch_to.frame(iframe)

    # 切换到默认窗口
    def switch_to_default(self):
        self.browser.switch_to.default_content()

    # 切换不同页面窗口
    def switch_to_window_by_title(self, title):
        for handle in self.browser.window_handles:
            self.browser.switch_to.window(handle)
            if self.browser.title == title:
                break
            self.browser.switch_to.default_content()

    # 执行js脚本
    def execute_js(self, src):
        self.browser.execute_script(src)

    # 截取图片,并保存在screenshot文件夹
    @property
    def get_screenshot(self):
        timestrmap = time.strftime('%Y%m%d_%H.%M.%S')
        imgPath = os.path.join(G.SCREENSHOT_DIR, f"{timestrmap}.png")
        self.browser.save_screenshot(imgPath)
        return imgPath

    # 控件截图为base64
    def save_element_snapshot_by_io(self, selector):
        el = self._locate_element(selector)
        return el.screenshot_as_base64

    # cookie 相关方法
    # 在driver初始化后清除cookie
    def clear_cookies(self):
        self.browser.delete_all_cookies()

    # 添加cookie，类型为dict
    def add_cookies(self, cookies):
        self.browser.add_cookie(cookie_dict=cookies)

    def add_cookie(self, cookie_dict):
        """
        Add single cookie by dict
        添加 单个 cookie
        如果该 cookie 已经存在，就先删除后，再添加
        :param cookie_dict: 字典类型，有两个key：name 和 value
        :return:
        """
        cookie_name = cookie_dict["name"]
        cookie_value = self.browser.get_cookie(cookie_name)
        if cookie_value is not None:
            self.browser.delete_cookie(cookie_name)
        self.browser.add_cookie(cookie_dict)

    def remove_cookie(self, name):
        """
        移除指定 name 的cookie
        :param name:
        :return:
        """
        # 检查 cookie 是否存在，存在就移除
        old_cookie_value = self.browser.get_cookie(name)
        if old_cookie_value is not None:
            self.browser.delete_cookie(name)

    # 浏览器本身相关方法
    def refresh(self, url=None):
        """
        刷新页面
        如果 url 是空值，就刷新当前页面，否则就刷新指定页面
        :param url: 默认值是空的
        :return:
        """
        if url is None:
            self.browser.refresh()
        else:
            self.browser.get(url)

    def maximize_window(self):
        """
        最大化当前浏览器的窗口
        :return:
        """
        self.browser.maximize_window()

    def navigate(self, url):
        """
        打开 URL
        :param url:
        :return:
        """
        self.browser.get(url)

    def quit(self):
        """
        退出驱动
        :return:
        """
        self.browser.quit()

    def close_browser(self):
        """
        关闭浏览器
        :return:
        """
        self.browser.close()

    def _locate_elements(self, locator):
        """
        to locate element by selector
        :arg
        selector should be passed by an example with "i,xxx"
        "x,//*[@id='langs']/button"
        :returns
        DOM element
        """
        if locator is not None:
            elements = self.browser.find_elements(*locator)
        else:
            raise NameError("Please enter a valid locator of targeting elements.")
        return elements

    def move_to(self, selector):
        """
        移动鼠标到指定元素
        :param selector:
        :return:
        """
        el = self._locate_element(selector)
        ActionChains(self.browser).move_to_element(el).perform()

    def right_click(self, selector):
        """
        鼠标右击
        :param selector:
        :return:
        """
        el = self._locate_element(selector)
        ActionChains(self.browser).context_click(el).perform()

    def double_click(self, selector):
        '''
        鼠标双击
        :param selector: （想要双击的元素）元素定位
        :return: 无
        '''
        ele = self._locate_element(selector)
        ActionChains(self.browser).double_click(ele).perform()

    def count_elements(self, selector):
        """
        数一下元素的个数
        :param selector: 定位符
        :return:
        """
        els = self._locate_elements(selector)
        return len(els)

    def drag_element(self, source, target):
        """
        拖拽元素
        :param source:
        :param target:
        :return:
        """
        el_source = self._locate_element(source)
        el_target = self._locate_element(target)

        if self.browser.w3c:
            ActionChains(self.browser).drag_and_drop(el_source, el_target).perform()
        else:
            ActionChains(self.browser).click_and_hold(el_source).perform()
            ActionChains(self.browser).move_to_element(el_target).perform()
            ActionChains(self.browser).release(el_target).perform()

    def lost_focus(self):
        """
        当前元素丢失焦点
        :return:
        """
        ActionChains(self.browser).key_down(Keys.TAB).key_up(Keys.TAB).perform()

    # 上传文件
    def upload_input(self, selector, file):
        '''
        上传文件 （ 标签为 input 类型，此类型最常见，最简单）
        :param selector: 上传按钮定位
        :param file: 将要上传的文件（绝对路径）
        :return: 无
        '''
        self._locate_element(selector).send_keys(file)

    def upload_not_input(self, file, browser_type='Chrome'):
        '''
        上传文件 （ 标签不是 input 类型，使用 win32gui,得先安装 pywin32 依赖包）
                                                pip install pywin32
        :param browser_type: 浏览器类型（Chrome浏览器和Firefox浏览器的有区别）
        :param file: 将要上传的文件（绝对路径）
        单个文件：file1 = 'C:\\Users\\list_tuple_dict_test.py'
        同时上传多个文件：file2 = '"C:\\Users\\list_tuple_dict_test.py" "C:\\Users\\class_def.py"'
        :return: 无
        '''
        # Chrome 浏览器是'打开'
        # 对话框
        # 下载个 Spy++ 工具，定位“打开”窗口，定位到窗口的类(L):#32770, '打开'为窗口标题
        if browser_type == 'Chrome':
            dialog = win32gui.FindWindow('#32770', u'打开')
        elif browser_type == 'Firefox':
            # Firefox 浏览器是'文件上传'
            # 对话框
            dialog = win32gui.FindWindow('#32770', u'文件上传')
        ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)
        ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
        # 上面三句依次寻找对象，直到找到输入框Edit对象的句柄
        Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)
        # 确定按钮Button
        button = win32gui.FindWindowEx(dialog, 0, 'Button', None)
        # 往输入框输入绝对地址
        win32gui.SendMessage(Edit, win32con.WM_SETTEXT, None, file)
        # 按button
        win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)
        # 获取属性
        # print(upload.get_attribute('value'))
